/*
 * @Author:your name
 * @Date:2020-11-09 23:03:52
 * @LastEditTime:2020-11-14 12:02:02
 * @LastEditors:Please set LastEditors
 * @Description:In User Settings Edit
 * @FilePath:\STM32F103_FreeRTOS\User\app\shell\shell_hash.c
 */ 

#include "shell_hash.h"
#include <stdlib.h>
#include <string.h>

static inline uint32_t _hash_calc(char *key, uint16_t keylen);
static inline uint16_t _hash_bucket_calc(uint32_t hash_value);

void hash_init(hash_table_t *table)
{
    uint16_t index = 0;
    for(index = 0; index < HASH_MAX_BUCKETS_NUM; ++index)
    {
        table->buckets[index].head = NULL;
        table->buckets[index].tail = NULL;
        table->buckets[index].node_num = 0;
    }
}

boolean hash_find(hash_table_t *table, char *key, uint16_t keylen, uint16_t *pvalue)
{
    uint16_t index = 0;

    index = _hash_bucket_calc(_hash_calc(key, keylen));
    hash_bucket_t *bucket = &table->buckets[index];
    if(bucket->node_num == 0)
        return FALSE;
    
    hash_node_t *tmp_node = bucket->head;
    for(index = 0; index < bucket->node_num; ++index)
    {
        if(0 == strcmp(tmp_node->data.key, key))
        {
            *pvalue = tmp_node->data.value;
            return TRUE;
        }
    }
    return FALSE;
}

/**
 * @brief: Add the 
 * @param {type}  
 * @retval: 
 * @return: 
 */
void hash_add(hash_table_t *table, char *key, uint16_t keylen, uint16_t value)
{
    uint16_t bucket_index = 0;
    uint32_t hash_value = 0;

    hash_node_t *new_node = (hash_node_t *)malloc(sizeof(hash_node_t));
    if(new_node == NULL)
        return;
    
    new_node->data.key = key;
    new_node->data.keylen = keylen;
    new_node->data.value = value;
    hash_value = _hash_calc(key, keylen);
    bucket_index = _hash_bucket_calc(hash_value);
    
    hash_bucket_t *bucket = &table->buckets[bucket_index];
    if(bucket->node_num == 0)
    {
        new_node->next = new_node;
        new_node->prev = new_node;
        bucket->head = new_node;
        bucket->tail = new_node;
    }
    else
    {
        new_node->next = bucket->head;
        new_node->prev = bucket->tail;
        bucket->head->prev = new_node;
        bucket->tail->next = new_node;
        bucket->head = new_node;
    }
    bucket->node_num++;
}

/**
 * @brief: Calculate the hash value
 * @param[in]: {char *} pointer to the key
 * @param[in]: {uint16_t} the key length
 * @retval: {uint32_t} hash value
 * @return: 
 */
static inline uint32_t _hash_calc(char *key, uint16_t keylen)
{
    return 0;
}

/**
 * @brief: Transfer the hash value to the bucket index
 * @param {uint32_t} hash value
 * @retval: {uint16_t} bucket index
 * @return: 
 */
static inline uint16_t _hash_bucket_calc(uint32_t hash_value)
{
    return (uint16_t)(hash_value & (HASH_MAX_BUCKETS_NUM - 1));
}

